#pragma once

#include "TcpServer.hpp"
#include "Common.hpp"
#include "HttpProtocol.hpp"

// 创建操作类型（比如注册，登录操作，会传递参数）
using http_handler_t = std::function<void(HttpRequest &, HttpResponse &)>;

class HttpServer
{
public:
    HttpServer(int port)
        : _tsvr(std::make_unique<TcpServer>(port))
    {
    }
    ~HttpServer() {}

    void Start()
    {
        // 这里需要访问 _tsvr 和其他成员变量
        // 需要 this 指针！
        _tsvr->InitServer([this](SockPtr sockfd, InetAddr client) -> bool
                          { return this->HandlerHttpRequest(sockfd, client); });

        _tsvr->Loop();
    }

    void Resgiter(std::string funcname,http_handler_t func)
    {
        _route[funcname]=func;
    }

    bool SafeCheck(const std::string &service)
    {
        auto it = _route.find(service);

        return it != _route.end();
    }

    bool HandlerHttpRequest(SockPtr sockfd, InetAddr client)
    {
        // 我们处理http的入口，在这里我们就可以实现我们的处理方法了
        LOG(LogLevel::DEBUG) << "HttpServer: get a new client: " << sockfd->Fd() << " addr info: " << client.Addr();

        std::string http_request; // 用来存储接收请求信息
        sockfd->Recv(&http_request);
        LOG(LogLevel::DEBUG) << "http_request:" << http_request;
        HttpRequest req;
        req.Deserialize(http_request); // 进行反序列化

        LOG(LogLevel::DEBUG) << "用户想要：" << req.Uri(); // 我们这里封装了一个Uri接口，就是单纯的返回_uri类成员变量

        // 随后我们需要对用户想要的URL的内容进行处理，包括判断URL的文件是否存在，如果存在，就读取内容
        // 构建响应
        HttpResponse resp;

        // 这里要注意了，由于我们的http方法不同，请求会被分为两类：
        //  1、 请求一般的静态资源（比如get）  2、 提交参数，携带参数的url申请，需要我们进行交互设置
        if (req.IsHasArgs()) // 是否有参数
        {
            LOG(LogLevel::DEBUG) << "处理带参URL";
            std::string service = req.Path();
            if (SafeCheck(service))//进行一个安全检查
            {
                _route[service](req, resp);
            }
            else
            {
                resp.Build(req);
            }
        }
        else // 没有就是正常的申请静态资源直接进入build逻辑就行了
        {
            LOG(LogLevel::DEBUG) << "申请静态资源";
            resp.Build(req); // 必须调用Build来设置内容和状态码
        }

        std::string resp_str; // 这是一个空字符串，我们需要通过响应结构体的序列化，进入响应结构体中带出我们的响应回复字符串

        // 进行序列化
        resp.Serialize(&resp_str);

        // LOG(LogLevel::DEBUG) << "resp_str:" << resp_str;
        sockfd->Send(resp_str);
        return true;

        // 我们通过Recv获取了用户端发送来的请求，就需要解析它，并给予反馈，进行文本处理
        // 1、读取请求的完整性
        // 2、完整http反序列化，http response序列化

        // std::string status_line = "HTTP/1.1 200 OK" + Sep + Blankline;
        // // 我们这里做实验就不需要返回响应报头，直接接空行表示响应报头为空

        // // 空行后面就是我们的响应正文：
        // std::string body = "<!DOCTYPE html>\
        // <html><head><title>\
        //  Hello World</title>\
        //  </head><body>\
        //  Hello,World !\
        //  </body> </html>";

        // std::string httprespnse = status_line + body;
        // sockfd->Send(httprespnse);
        // return true;
    }

private:
    std::unique_ptr<TcpServer> _tsvr; // 由于http是由TCP实现的，所以我们肯定内部一定会有一个TCP服务

    std::unordered_map<std::string, http_handler_t> _route; // 充当一个功能路由
};